from collections.abc import Generator
import time

from assertpy import assert_that
from kubernetes.client import V1Pod
from playwright.sync_api import Page, BrowserContext
import pytest

from utils.client import KubeClient, StressConfig
import actions.colocation.colocation_configuration as cc


# 根据集群的实际硬件资源调整下面的值
THRESHOLD_LOW = 10
THRESHOLD_HIGH = 90
STRESS_LOAD = 60
HLS_RESOURCES = {
    "requests": {
        "cpu": "1",
        "memory": "8Gi",
    },
    "limits": {
        "cpu": "1",
        "memory": "8Gi",
    },
}


@pytest.fixture(scope="function")
def conf_page(context: BrowserContext) -> Generator[Page, None, None]:
    """打开弹窗并打开离线负载水位线驱逐按钮，不填写水位线阈值，不点击确认"""
    page = context.new_page()
    cc.visit_colocation_config_page(page)
    cc.do_open_modal(page)
    if not cc.get_eviction_switch(page).is_checked():
        cc.do_toggle_eviction_switch(page)
    cc.do_click_modal_confirm(page)
    yield page

    cc.do_open_modal(page)
    if cc.get_eviction_switch(page).is_checked():
        cc.do_toggle_eviction_switch(page)
        cc.do_click_modal_confirm(page)
    page.close()


@pytest.fixture(scope="module")
def stress_pod(kube_client: KubeClient) -> Generator[V1Pod, None, None]:
    stress_pod = kube_client.deploy_stress_pod(HLS_RESOURCES)
    yield stress_pod

    name, ns = stress_pod.metadata.name, stress_pod.metadata.namespace
    kube_client.delete_pod(name, ns, 60)


@pytest.fixture(scope="function")
def stress_up_cpu(kube_client: KubeClient, stress_pod: V1Pod, numa_stat: dict) -> Generator[None, None]:
    kube_client.start_stress_process(
        name=stress_pod.metadata.name,
        namespace=stress_pod.metadata.namespace,
        stress_config=StressConfig(
            cpu_core=numa_stat["cpus"], 
            cpu_load=STRESS_LOAD,
        )
    )
    time.sleep(10)
    yield

    kube_client.stop_stress_process()


@pytest.fixture(scope="function")
def stress_up_memory(kube_client: KubeClient, stress_pod: V1Pod, numa_stat: dict) -> Generator[None, None]:
    kube_client.start_stress_process(
        name=stress_pod.metadata.name,
        namespace=stress_pod.metadata.namespace,
        stress_config=StressConfig(
            vm=1,
            vm_bytes=STRESS_LOAD,
        ),
    )
    time.sleep(10)
    yield

    kube_client.stop_stress_process()


def update_threshold(page: Page, cpu: int = 0, mem: int = 0, wait_time: int = 5):
    cc.do_open_modal(page)
    cpu_box, mem_box = cc.get_eviction_threshold_textbox(page)
    if cpu > 0 and cpu < 100:
        cpu_box.fill(str(cpu))
    if mem > 0 and mem < 100:
        mem_box.fill(str(mem))
    cc.do_click_modal_confirm(page)
    time.sleep(wait_time)


class TestEvictionOn:
    """
     @description 测试**离线负载水位线驱逐**特性开启时的调度
     [WARING] 节点 CPU 核数不足时，可能发生LS、HLS无法部署
    """
    @pytest.mark.usefixtures("stress_up_cpu")
    @staticmethod
    def test_cpu_reaches_threshold(kube_client: KubeClient, conf_page: Page):
        """Test 77, 80, 81"""
        # 利用率大于阈值
        update_threshold(conf_page, THRESHOLD_LOW, 99)
        # BE 被驱逐
        pod = kube_client.install_be_pod()
        name, ns = pod.metadata.name, pod.metadata.namespace
        try:
            assert_that(kube_client.wait_pod_delete(name, ns)).is_true()
        finally:
            kube_client.delete_pod(name, ns)
        # LS/HLS 不被驱逐
        for install_func in [kube_client.install_ls_pod, kube_client.install_hls_pod]:
            pod = install_func()
            name, ns = pod.metadata.name, pod.metadata.namespace
            assert_that(kube_client.wait_pod_condition(name, ns, "Running")).is_true()
            kube_client.delete_pod(name, ns)

        # 利用率低于阈值，均不被驱逐
        update_threshold(conf_page, THRESHOLD_HIGH, 99)
        for install_func in [kube_client.install_be_pod, kube_client.install_ls_pod, kube_client.install_hls_pod]:
            pod = install_func()
            name, ns = pod.metadata.name, pod.metadata.namespace
            assert_that(kube_client.wait_pod_condition(name, ns, "Running")).is_true()
            kube_client.delete_pod(name, ns)

    @pytest.mark.usefixtures("stress_up_memory")
    @staticmethod
    def test_memory_reaches_threshold(kube_client: KubeClient, conf_page: Page):
        """Test 79, 82, 83"""
        # 利用率大于阈值
        update_threshold(conf_page, 99, THRESHOLD_LOW)
        # BE 被驱逐
        pod = kube_client.install_be_pod()
        name, ns = pod.metadata.name, pod.metadata.namespace
        try:
            assert_that(kube_client.wait_pod_delete(name, ns))
        finally:
            kube_client.delete_pod(name, ns)
        # LS/HLS 不被驱逐
        for install_func in [kube_client.install_ls_pod, kube_client.install_hls_pod]:
            pod = install_func()
            name, ns = pod.metadata.name, pod.metadata.namespace
            assert_that(kube_client.wait_pod_condition(name, ns, "Running"))
            kube_client.delete_pod(name, ns)

        # 利用率低于阈值，均不被驱逐
        update_threshold(conf_page, 99, THRESHOLD_HIGH)
        for install_func in [kube_client.install_be_pod, kube_client.install_ls_pod, kube_client.install_hls_pod]:
            pod = install_func()
            name, ns = pod.metadata.name, pod.metadata.namespace
            assert_that(kube_client.wait_pod_condition(name, ns, "Running"))
            kube_client.delete_pod(name, ns)